package Forms;

import java.awt.Dimension;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;

import javax.swing.JMenuBar;
import javax.swing.JButton;
import javax.swing.JMenu;
import javax.swing.JLabel;
import javax.swing.GroupLayout;
import javax.swing.JOptionPane;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.JScrollPane;

import Logic.DatabaseReader;
import Logic.Registration;

import javax.swing.JSpinner;
import javax.swing.SpinnerListModel;

public class MainForm extends JFrame {

	private JPanel contentPane;
	private JTextField departureLocationField;
	private JTextField arrivalLocationField;
	private JTextField maximumPriceField;
	private JTextField classField;
	private LoginPanel loginPanel;
	private JPanel flightsPanel;
	private JTabbedPane tabbedPane;
	private UserInfoPanel userInfoPanel;
	private JSpinner yearSpinner;
	private JSpinner monthSpinner;
	private JSpinner daySpinner;

	private JTable availableFlightsTable;

	private JButton tripDetailsButton;

	private DatabaseReader databaseReader;

	// contains the trips corresponding to the search-parameters of the user.
	// every trip contains different informations (contained inside the array)
	private LinkedList<String[]> availableFlightsList;
	
	private JLabel errorLabel;

	private String currentUserID = "";

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					MainForm frame = new MainForm();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public MainForm()
	{
		setBackground(Color.WHITE);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 520, 400);
		contentPane = new JPanel();
		contentPane.setBackground(Color.WHITE);
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(null);
		setContentPane(contentPane);
		databaseReader = new DatabaseReader();

		loginPanel = new LoginPanel(this, "main");

		tabbedPane = new JTabbedPane(JTabbedPane.TOP);
		tabbedPane.setBounds(0, 25, 800, 550);

		JPanel bookingPane = new JPanel();
		bookingPane.setLayout(null);

		JMenuBar mainMenuBar = new JMenuBar();
		mainMenuBar.setBounds(0, 0, 800, 25);
		contentPane.add(mainMenuBar);

		JMenu userMenuItem = new JMenu("User");

		JMenu databaseMenueItem = new JMenu("Database");
		mainMenuBar.add(userMenuItem);
		mainMenuBar.add(databaseMenueItem);

		JButton databaseManagerButton = new JButton("Manage");
		databaseManagerButton.setToolTipText("Manage database");
		JButton connectDatabaseButton = new JButton("Connect");
		connectDatabaseButton.setToolTipText("Connect database");
		connectDatabaseButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0)
			{
				new DatabaseConnector(databaseReader);
			}
		});

		databaseManagerButton.addActionListener(new LaunchAdminFrame());
		databaseMenueItem.add(databaseManagerButton);
		databaseMenueItem.add(connectDatabaseButton);

		JButton logoutButton = new JButton("Log out");
		logoutButton.setToolTipText("Log off current user");
		logoutButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e)
			{
				logOut();
			}
		});
		userMenuItem.add(logoutButton);

		JPanel searchPanel = new JPanel();
		searchPanel.setBackground(new Color(255, 215, 0));
		searchPanel.setBounds(0, 0, 800, 122);

		JLabel departureLocationLabel = new JLabel("Departure Location: ");

		JLabel arrivalLocationLabel = new JLabel("Arrival Location:");

		JLabel departureDateLabel = new JLabel("Date of Departure:");

		departureLocationField = new JTextField();
		departureLocationField.setColumns(10);

		arrivalLocationField = new JTextField();
		arrivalLocationField.setColumns(10);

		JLabel maximumPriceLabel = new JLabel("Maximum Price:");

		JLabel classLabel = new JLabel("Class: ");

		maximumPriceField = new JTextField();
		maximumPriceField.setColumns(10);

		classField = new JTextField();
		classField.setColumns(10);

		JButton SearchButton = new JButton("Search");
		SearchButton.setToolTipText("Search entity in database with the given parameters");
		SearchButton.addActionListener(new SearchFlights(databaseReader));

		JLabel euroLabel = new JLabel("€");

		yearSpinner = new JSpinner();
		yearSpinner.setModel(new SpinnerListModel(new String[] { "", "2012",
				"2013", "2014" }));

		monthSpinner = new JSpinner();
		monthSpinner.setModel(new SpinnerListModel(new String[] { "", "01",
				"02", "03", "04", "05", "06", "07", "08", "09", "10", "11",
				"12" }));

		daySpinner = new JSpinner();
		daySpinner.setModel(new SpinnerListModel(new String[] { "", "01", "02",
				"03", "04", "05", "06", "07", "08", "09", "10", "11", "12",
				"13", "14", "15", "16", "17", "18", "19", "20", "21", "22",
				"23", "24", "25", "26", "27", "28" }));

		GroupLayout gl_searchPanel = new GroupLayout(searchPanel);
		gl_searchPanel
				.setHorizontalGroup(gl_searchPanel
						.createParallelGroup(Alignment.LEADING)
						.addGroup(
								gl_searchPanel
										.createSequentialGroup()
										.addContainerGap()
										.addGroup(
												gl_searchPanel
														.createParallelGroup(
																Alignment.LEADING)
														.addComponent(
																departureLocationLabel)
														.addComponent(
																arrivalLocationLabel)
														.addComponent(
																departureDateLabel))
										.addPreferredGap(
												ComponentPlacement.RELATED)
										.addGroup(
												gl_searchPanel
														.createParallelGroup(
																Alignment.LEADING)
														.addComponent(
																departureLocationField,
																GroupLayout.PREFERRED_SIZE,
																GroupLayout.DEFAULT_SIZE,
																GroupLayout.PREFERRED_SIZE)
														.addComponent(
																arrivalLocationField,
																GroupLayout.PREFERRED_SIZE,
																GroupLayout.DEFAULT_SIZE,
																GroupLayout.PREFERRED_SIZE))
										.addGroup(
												gl_searchPanel
														.createParallelGroup(
																Alignment.TRAILING)
														.addGroup(
																gl_searchPanel
																		.createSequentialGroup()
																		.addGap(78)
																		.addGroup(
																				gl_searchPanel
																						.createParallelGroup(
																								Alignment.LEADING)
																						.addComponent(
																								maximumPriceLabel)
																						.addComponent(
																								classLabel))
																		.addPreferredGap(
																				ComponentPlacement.UNRELATED)
																		.addGroup(
																				gl_searchPanel
																						.createParallelGroup(
																								Alignment.LEADING)
																						.addComponent(
																								classField,
																								GroupLayout.PREFERRED_SIZE,
																								GroupLayout.DEFAULT_SIZE,
																								GroupLayout.PREFERRED_SIZE)
																						.addComponent(
																								maximumPriceField,
																								GroupLayout.PREFERRED_SIZE,
																								GroupLayout.DEFAULT_SIZE,
																								GroupLayout.PREFERRED_SIZE))
																		.addContainerGap(
																				196,
																				Short.MAX_VALUE))
														.addGroup(
																gl_searchPanel
																		.createSequentialGroup()
																		.addPreferredGap(
																				ComponentPlacement.RELATED)
																		.addComponent(
																				SearchButton)
																		.addContainerGap()))));
		gl_searchPanel
				.setVerticalGroup(gl_searchPanel
						.createParallelGroup(Alignment.LEADING)
						.addGroup(
								gl_searchPanel
										.createSequentialGroup()
										.addContainerGap()
										.addGroup(
												gl_searchPanel
														.createParallelGroup(
																Alignment.BASELINE)
														.addComponent(
																departureLocationLabel)
														.addComponent(
																departureLocationField,
																GroupLayout.PREFERRED_SIZE,
																GroupLayout.DEFAULT_SIZE,
																GroupLayout.PREFERRED_SIZE)
														.addComponent(
																maximumPriceLabel)
														.addComponent(
																maximumPriceField,
																GroupLayout.PREFERRED_SIZE,
																GroupLayout.DEFAULT_SIZE,
																GroupLayout.PREFERRED_SIZE))
										.addGap(18)
										.addGroup(
												gl_searchPanel
														.createParallelGroup(
																Alignment.BASELINE)
														.addComponent(
																arrivalLocationLabel)
														.addComponent(
																arrivalLocationField,
																GroupLayout.PREFERRED_SIZE,
																GroupLayout.DEFAULT_SIZE,
																GroupLayout.PREFERRED_SIZE)
														.addComponent(
																classLabel)
														.addComponent(
																classField,
																GroupLayout.PREFERRED_SIZE,
																GroupLayout.DEFAULT_SIZE,
																GroupLayout.PREFERRED_SIZE))
										.addGap(18)
										.addGroup(
												gl_searchPanel
														.createParallelGroup(
																Alignment.BASELINE)
														.addComponent(
																departureDateLabel)
														.addComponent(
																SearchButton))
										.addContainerGap(29, Short.MAX_VALUE)));
		gl_searchPanel
				.setHorizontalGroup(gl_searchPanel
						.createParallelGroup(Alignment.LEADING)
						.addGroup(
								gl_searchPanel
										.createSequentialGroup()
										.addContainerGap()
										.addGroup(
												gl_searchPanel
														.createParallelGroup(
																Alignment.LEADING)
														.addComponent(
																departureLocationLabel)
														.addComponent(
																arrivalLocationLabel)
														.addComponent(
																departureDateLabel))
										.addPreferredGap(
												ComponentPlacement.RELATED)
										.addGroup(
												gl_searchPanel
														.createParallelGroup(
																Alignment.LEADING,
																false)
														.addComponent(
																departureLocationField)
														.addGroup(
																gl_searchPanel
																		.createSequentialGroup()
																		.addComponent(
																				yearSpinner,
																				GroupLayout.PREFERRED_SIZE,
																				58,
																				GroupLayout.PREFERRED_SIZE)
																		.addPreferredGap(
																				ComponentPlacement.RELATED)
																		.addComponent(
																				monthSpinner,
																				GroupLayout.PREFERRED_SIZE,
																				42,
																				GroupLayout.PREFERRED_SIZE)
																		.addPreferredGap(
																				ComponentPlacement.RELATED)
																		.addComponent(
																				daySpinner))
														.addComponent(
																arrivalLocationField,
																GroupLayout.PREFERRED_SIZE,
																153,
																GroupLayout.PREFERRED_SIZE))
										.addGroup(
												gl_searchPanel
														.createParallelGroup(
																Alignment.LEADING)
														.addGroup(
																gl_searchPanel
																		.createSequentialGroup()
																		.addGap(84)
																		.addGroup(
																				gl_searchPanel
																						.createParallelGroup(
																								Alignment.LEADING)
																						.addComponent(
																								maximumPriceLabel)
																						.addGroup(
																								gl_searchPanel
																										.createSequentialGroup()
																										.addGap(67)
																										.addComponent(
																												classLabel)))
																		.addPreferredGap(
																				ComponentPlacement.UNRELATED)
																		.addGroup(
																				gl_searchPanel
																						.createParallelGroup(
																								Alignment.LEADING)
																						.addGroup(
																								gl_searchPanel
																										.createSequentialGroup()
																										.addComponent(
																												maximumPriceField,
																												GroupLayout.PREFERRED_SIZE,
																												GroupLayout.DEFAULT_SIZE,
																												GroupLayout.PREFERRED_SIZE)
																										.addGap(4)
																										.addComponent(
																												euroLabel))
																						.addComponent(
																								classField,
																								GroupLayout.PREFERRED_SIZE,
																								GroupLayout.DEFAULT_SIZE,
																								GroupLayout.PREFERRED_SIZE))
																		.addContainerGap())
														.addGroup(
																Alignment.TRAILING,
																gl_searchPanel
																		.createSequentialGroup()
																		.addPreferredGap(
																				ComponentPlacement.RELATED,
																				357,
																				Short.MAX_VALUE)
																		.addComponent(
																				SearchButton)
																		.addGap(36)))));
		gl_searchPanel
				.setVerticalGroup(gl_searchPanel
						.createParallelGroup(Alignment.LEADING)
						.addGroup(
								gl_searchPanel
										.createSequentialGroup()
										.addContainerGap()
										.addGroup(
												gl_searchPanel
														.createParallelGroup(
																Alignment.BASELINE)
														.addComponent(
																departureLocationLabel)
														.addComponent(
																departureLocationField,
																GroupLayout.PREFERRED_SIZE,
																GroupLayout.DEFAULT_SIZE,
																GroupLayout.PREFERRED_SIZE)
														.addComponent(
																maximumPriceLabel)
														.addComponent(
																maximumPriceField,
																GroupLayout.PREFERRED_SIZE,
																GroupLayout.DEFAULT_SIZE,
																GroupLayout.PREFERRED_SIZE)
														.addComponent(euroLabel))
										.addGap(18)
										.addGroup(
												gl_searchPanel
														.createParallelGroup(
																Alignment.BASELINE)
														.addComponent(
																arrivalLocationLabel)
														.addComponent(
																arrivalLocationField,
																GroupLayout.PREFERRED_SIZE,
																GroupLayout.DEFAULT_SIZE,
																GroupLayout.PREFERRED_SIZE)
														.addComponent(
																classLabel)
														.addComponent(
																classField,
																GroupLayout.PREFERRED_SIZE,
																GroupLayout.DEFAULT_SIZE,
																GroupLayout.PREFERRED_SIZE))
										.addGap(18)
										.addGroup(
												gl_searchPanel
														.createParallelGroup(
																Alignment.BASELINE)
														.addComponent(
																departureDateLabel)
														.addComponent(
																yearSpinner,
																GroupLayout.PREFERRED_SIZE,
																GroupLayout.DEFAULT_SIZE,
																GroupLayout.PREFERRED_SIZE)
														.addComponent(
																monthSpinner,
																GroupLayout.PREFERRED_SIZE,
																GroupLayout.DEFAULT_SIZE,
																GroupLayout.PREFERRED_SIZE)
														.addComponent(
																daySpinner,
																GroupLayout.PREFERRED_SIZE,
																GroupLayout.DEFAULT_SIZE,
																GroupLayout.PREFERRED_SIZE)
														.addComponent(
																SearchButton))
										.addContainerGap(
												GroupLayout.DEFAULT_SIZE,
												Short.MAX_VALUE)));
		searchPanel.setLayout(gl_searchPanel);

		flightsPanel = new JPanel();
		flightsPanel.setBackground(Color.WHITE);
		flightsPanel.setBounds(0, 122, 800, 555);

		JScrollPane availableFlightsScrollPane = new JScrollPane();

		tripDetailsButton = new JButton("Show Details");
		tripDetailsButton.addActionListener(new DisplayTripDetails(
				databaseReader));
		tripDetailsButton
				.setToolTipText("Display details about the selected trip");

		errorLabel = new JLabel("                  ");
		errorLabel.setForeground(Color.RED);

		GroupLayout gl_flightsPanel = new GroupLayout(flightsPanel);
		gl_flightsPanel.setHorizontalGroup(gl_flightsPanel
				.createParallelGroup(Alignment.TRAILING)
				.addComponent(availableFlightsScrollPane,
						GroupLayout.DEFAULT_SIZE, 800, Short.MAX_VALUE)
				.addGroup(
						gl_flightsPanel
								.createSequentialGroup()
								.addContainerGap()
								.addComponent(errorLabel)
								.addPreferredGap(ComponentPlacement.RELATED,
										577, Short.MAX_VALUE)
								.addComponent(tripDetailsButton)
								.addContainerGap()));
		gl_flightsPanel
				.setVerticalGroup(gl_flightsPanel
						.createParallelGroup(Alignment.LEADING)
						.addGroup(
								gl_flightsPanel
										.createSequentialGroup()
										.addContainerGap()
										.addComponent(
												availableFlightsScrollPane,
												GroupLayout.PREFERRED_SIZE,
												339, GroupLayout.PREFERRED_SIZE)
										.addPreferredGap(
												ComponentPlacement.RELATED)
										.addGroup(
												gl_flightsPanel
														.createParallelGroup(
																Alignment.BASELINE)
														.addComponent(
																tripDetailsButton)
														.addComponent(
																errorLabel))
										.addContainerGap(153, Short.MAX_VALUE)));
		tripDetailsButton.setEnabled(false);

		availableFlightsTable = new JTable();
		availableFlightsTable.setBackground(Color.WHITE);
		availableFlightsScrollPane.setViewportView(availableFlightsTable);
		availableFlightsTable
				.setModel(new DefaultTableModel(new Object[][] {},
						new String[] { "Departure Date", "Departure Location",
								"Arrival Date", "Arrival Location", "Changes",
								"Price" }) {
					boolean[] columnEditables = new boolean[] { false, false,
							false, false, false, false };

					public boolean isCellEditable(int row, int column) {
						return columnEditables[column];
					}
				});

		userInfoPanel = new UserInfoPanel(databaseReader.getConnection(),
				currentUserID);

		flightsPanel.setLayout(gl_flightsPanel);
		bookingPane.add(searchPanel);
		bookingPane.add(flightsPanel);
		tabbedPane.addTab("Booking", null, bookingPane, null);
		tabbedPane.addTab("User Info", userInfoPanel);
		tabbedPane.addChangeListener(new ChangeListener() {

			public void stateChanged(ChangeEvent changeEvent) {
				JTabbedPane sourceTabbedPane = (JTabbedPane) changeEvent
						.getSource();
				if (sourceTabbedPane.getSelectedIndex() == 1) {
					userInfoPanel.addData(currentUserID, databaseReader.getConnection());
				}

			}
		});

		contentPane.add(loginPanel);

		this.setPreferredSize(new Dimension(800, 600));
		this.setResizable(false);
		pack();
	}

	/**
	 * Displays the LoginPanel.
	 * If the login-informations are correct, it passes specific informations about the user to the UserInfoPanel
	 * and displays and passes control to the standard tabbedPane.
	 */
	public boolean logOn(String userID, String pwd) {
		if (databaseReader.isDatabaseConnected()) {
			if (databaseReader.logOn(userID, pwd)) {
				contentPane.remove(loginPanel);
				contentPane.add(tabbedPane);
				this.currentUserID = userID;
				userInfoPanel.addData(userID,databaseReader.getConnection());
				repaint();
				pack();
				return true;
			} else {
				JOptionPane.showMessageDialog(this,
						"Login Failed: User or password incorrect!");
				return false;
			}
		} else {
			JOptionPane.showMessageDialog(this, "No Database connected!");
			return false;
		}
	}
	
	/**
	 * Logs out the actual user and resets the control again to the LoginPanel.
	 */
	public void logOut() {
		if (currentUserID.equals("")) {
			JOptionPane.showMessageDialog(this,
					"No user logged in. Please log in first.");
		} else {
			int logout = JOptionPane.showConfirmDialog(this,
					"Do you really want to log out?");
			if (logout == JOptionPane.YES_OPTION) {
				contentPane.remove(tabbedPane);
				contentPane.add(loginPanel);
				this.currentUserID = "";
				clearComponents();
				repaint();
				pack();
			}
		}

	}

	public String registerUser(Registration registration) {
		return databaseReader.registerUser(registration);
	}

	class LaunchAdminFrame implements ActionListener {
		public void actionPerformed(ActionEvent arg0) {
			new AdminFrame(databaseReader);
		}
	}

	class SearchFlights implements ActionListener {
		DatabaseReader databaseReader;

		String departureLocation;
		String arrivalLocation;
		String departureDate;
		String maximumPrice;

		String[][] availableFlightsArray;

		public SearchFlights(DatabaseReader databaseReader) {
			this.databaseReader = databaseReader;
		}

		public void actionPerformed(ActionEvent arg0) {
			departureLocation = null;
			arrivalLocation = null;
			departureDate = "";
			maximumPrice = null;

			departureLocation = departureLocationField.getText();
			arrivalLocation = arrivalLocationField.getText();

			if (checkIfDateCorrect())
				departureDate = yearSpinner.getValue().toString() + "-"
						+ monthSpinner.getValue().toString() + "-"
						+ daySpinner.getValue().toString() + " 00:00:00";

			maximumPrice = maximumPriceField.getText();

			availableFlightsList = databaseReader.readFlights(
					departureLocation, arrivalLocation, departureDate,
					maximumPrice);

			if (availableFlightsList.size() > 0)
				tripDetailsButton.setEnabled(true);
			else
				tripDetailsButton.setEnabled(false);

			errorLabel.setText("");
			fillTable();
		}

		/**
		 * Fills the JTable with the informations about the trips corresponding to the passed search-parameters.
		 */
		private void fillTable() {
			DefaultTableModel model = (DefaultTableModel) availableFlightsTable.getModel();
			int nrOfRows = model.getRowCount();

			for (int q = 0; q < nrOfRows; q++) {
				model.removeRow(0);
			}

			for (String[] str : availableFlightsList) {
				model.addRow(str);
			}
		}

		/**
		 * Checks if the date combined through the corresponding JSliders does exist.
		 */
		private boolean checkIfDateCorrect() {
			if (yearSpinner.getValue() != "" && monthSpinner.getValue() != ""
					&& daySpinner.getValue() != "")
				return true;
			else
				return false;
		}
	}

	class DisplayTripDetails implements ActionListener {
		DatabaseReader databaseReader;
		LinkedList<String[]> flightInformations;
		int selectedRow;

		public DisplayTripDetails(DatabaseReader databaseReader) {
			this.databaseReader = databaseReader;
		}

		public void actionPerformed(ActionEvent arg0) {
			if (availableFlightsTable.getSelectedRowCount() == 1)
			{
				errorLabel.setText("");
				flightInformations = databaseReader.readFlightsInformations(availableFlightsTable.getSelectedRow());
				selectedRow = availableFlightsTable.getSelectedRow();

				new TripDetailsFrame(currentUserID, databaseReader,selectedRow, flightInformations,
						availableFlightsList.get(selectedRow));
			}
			else if (availableFlightsTable.getSelectedRowCount() > 1)
				errorLabel.setText("* You can just display the informations of one single trip");
			else
				errorLabel.setText("* You have to select one trip in order to display his informations");
		}
	}

	/**
	 * Deletes the entry inside the textfields.
	 */
	public void clearComponents() {

		errorLabel.setText("");
		departureLocationField.setText("");
		arrivalLocationField.setText("");
		maximumPriceField.setText("");
		classField.setText("");
		DefaultTableModel model = (DefaultTableModel) availableFlightsTable
				.getModel();
		int rowCount = model.getRowCount();
		for (int i = 0; i < rowCount; i++) {
			model.removeRow(0);
		}
		tripDetailsButton.setEnabled(false);

	}
	
	public boolean isDatabaseConnected(){
		return databaseReader.isDatabaseConnected();
	}
}
